﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConjureBivouac2012.Object;
using ConjureBivouac2012.World;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using ConjureBivouac2012.Mathematics;

namespace ConjureBivouac2012.GameStates
{
    public class PlayGame : IGlobalGameState
    {
        private Texture2D _background;

        private ContentManager _contentManager = null;
        private GraphicsDevice _device;

        private List<Entity> addingList;
        private List<Entity> deleteList;
        private List<Entity> mainList;
        private PlayerDeflecter player;
        private WorldMap world;
        private SpawnTimer spawnTimer;

        public PlayGame(ContentManager contentManager, GraphicsDevice device)
        {
            _contentManager = contentManager;
            _device = device;
            _background = contentManager.Load<Texture2D>("Stage");

            addingList = new List<Entity>();
            deleteList = new List<Entity>();
            mainList = new List<Entity>();
            world = new WorldMap(800, 600, 10);
            spawnTimer = new SpawnTimer();

            GameInfo.GetInstance().Initialize(contentManager, device);
        }

        public AbstractPlayer GetPlayer()
        {
            return player;
        }

        public List<Entity> GetEntityList()
        {
            return mainList;
        }

        public void Enter()
        {
            int speed = 80;
            // Initialisation du jeu
            mainList.Add(new VehiculeDeflecter());
            player                      = new PlayerDeflecter(PlayerIndex.One, (VehiculeDeflecter)mainList[0]);
            mainList[0].sprite.Position = new Vector2(GameInfo.GetInstance().GetDevice().Viewport.Width / 2 - mainList[0].sprite.Size.Width / 2,
                                                      GameInfo.GetInstance().GetDevice().Viewport.Height / 2 - mainList[0].sprite.Size.Height / 2);
            AbstractEnemy ennemy        = new BasicEnemy(4,-1);
            ennemy.setVelocity(new Vector2(speed, speed));
            ennemy.SetDirection(new Vector2(0.5f, 0.5f));
            ennemy.sprite.Position = new Vector2(0 + GameInfo.GetInstance().GetDevice().Viewport.Width/100 + ennemy.sprite.Size.Width/2,
                                                 0 + GameInfo.GetInstance().GetDevice().Viewport.Height/100 + ennemy.sprite.Size.Height/2);
            mainList.Add(ennemy);

            ennemy = new BasicEnemy( 4, -1);
            ennemy.setVelocity(new Vector2(speed, speed));
            ennemy.SetDirection(new Vector2(-0.5f, 0.5f));
            ennemy.sprite.Position = new Vector2(0 + GameInfo.GetInstance().GetDevice().Viewport.Width/100 + ennemy.sprite.Size.Width/2,
                                                 GameInfo.GetInstance().GetDevice().Viewport.Height - GameInfo.GetInstance().GetDevice().Viewport.Height / 100 - ennemy.sprite.Size.Height/2);
            mainList.Add(ennemy);

            ennemy = new BasicEnemy(4, -1);
            ennemy.setVelocity(new Vector2(speed, speed));
            ennemy.SetDirection(new Vector2(-0.5f, -0.5f));
            ennemy.sprite.Position = new Vector2(GameInfo.GetInstance().GetDevice().Viewport.Width - GameInfo.GetInstance().GetDevice().Viewport.Width/100 - ennemy.sprite.Size.Height/2,
                                                 GameInfo.GetInstance().GetDevice().Viewport.Height - GameInfo.GetInstance().GetDevice().Viewport.Height/100 - ennemy.sprite.Size.Height/2);
            mainList.Add(ennemy);
        }

        public void Execute(GameTime gameTime)
        {
            
            // STEP 0NE
            // Adding the new object
            mainList.AddRange(addingList);
            addingList.Clear();

            // STEP TW0
            // Movements of the entitys
            player.Update(gameTime);
            GameInfo.GetInstance().Execute(gameTime);
            foreach (Entity o in mainList) o.Update(gameTime);

            // STEP THREE
            // Special abilities
            Entity[] entitiesToBeAdded;
            foreach (Entity o in mainList)
            {
                entitiesToBeAdded = o.addingEntity();
                if (entitiesToBeAdded != null)
                {
                    foreach (Entity entity in entitiesToBeAdded)
                    {
                        addingList.Add(entity);
                    }
                }
            }

            // STEP F0UR
            // Detecting collisions
            for (int i = 0; i < mainList.Count; i++)
            {
                if (i < mainList.Count - 1)
                {
                    for (int j = (i + 1); j < mainList.Count; j++)
                    {
                        if (Phasik.Collision(mainList[i], mainList[j]))
                        {
                            if (mainList[i] is AbstractVehicule)
                            {
                                if (mainList[j] is AbstractPowerUp)
                                {
                                    ((AbstractPowerUp)mainList[j]).ApplyEffect(player);
                                }
                                else
                                {
                                    AbstractVehicule o = (AbstractVehicule)mainList[i];
                                    if (o.OnHurt(mainList[j].sprite.Position))
                                    {
                                        mainList[j].destroyMe();
                                    }
                                    else
                                    {
                                        mainList[j].canCollide();
                                        Phasik.rebound(mainList[i], mainList[j]);
                                    }
                                    
                                }
                                
                            }
                            else if (mainList[i] is AbstractEnemy)
                            {
                                if (mainList[j] is AbstractBullet && mainList[j].vulnerableTo == Entity.ENNEMY)
                                {
                                    mainList[i].destroyMe();
                                    mainList[j].destroyMe();
                                }
                                Phasik.rebound(mainList[i], mainList[j]);
                            }
                            else Phasik.rebound(mainList[i], mainList[j]);
                        }

                    }
                }

                if (mainList[i].hasToBeDestroyed())
                {
                    if (!deleteList.Contains(mainList[i]))
                    {
                        deleteList.Add(mainList[i]);
                    }
                }
            }

            player.UpdateShield();

            // STEP FIVE
            // Update le spawnTimer
            spawnTimer.Update(1);
            Entity[] spawn = spawnTimer.SpawnMonsters();
            if (spawn != null)
            {
                foreach (Entity o in spawn)
                {
                    addingList.Add(o);
                }
            }

            // STEP SIX
            // Suppression des elements
            foreach (Entity o in deleteList)
            {
                Entity dropped = o.DroppingEntity();
                if(dropped != null)
                {
                    addingList.Add(dropped);
                }
                mainList.Remove(o);
            }
            deleteList.Clear();
         
        }

        public void Exit()
        {

        }

        public void Draw(SpriteBatch theSpriteBatch)
        {
            //GameInfo.GetInstance().Draw(theSpriteBatch);

           theSpriteBatch.Draw(_background, new Rectangle(0, 0, _device.Viewport.Width, _device.Viewport.Height), null, Color.White, 0, new Vector2(0, 0),
                                        SpriteEffects.None, 1);
            foreach (Entity o in mainList) o.Draw(theSpriteBatch);
        }

        internal void SuperBombExploding()
        {
            foreach (var entity in mainList)
            {
                if (!(entity is AbstractVehicule) && !deleteList.Contains(entity))
                {
                    deleteList.Add(entity);
                }
            }
        }
    }
}
